using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design.Serialization;
using System.CodeDom;
using System.ComponentModel;

namespace XnaDesignerGenerator
{
    public class XnaGameServiceGenerator : CodeDomSerializer
    {
        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            //base.Serialize(manager, value);
            XnaGameService component = value as XnaGameService;
            CodeStatementCollection statements = new CodeStatementCollection();
            if (component != null)
            {
                statements.Add(new CodeCommentStatement(""));
                statements.Add(new CodeCommentStatement(" " + component.Site.Name));
                statements.Add(new CodeCommentStatement(""));
                //Initialisation de la variable component1
                statements.Add(new CodeVariableDeclarationStatement(
                    component.GetType(),
                    component.Site.Name,
                    new CodeObjectCreateExpression(component.GetType(), new CodeExpression[] { })));

                statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(
                        new CodeVariableReferenceExpression(component.Site.Name),
                        "Parent"),
                    new CodeThisReferenceExpression()));

                if (component.Project != null)
                    SerializeProperty(manager, statements, component, TypeDescriptor.GetProperties(component)["Project"]);

                //Instanciation d'un gameComponent
                if (component.ServiceInterface != null && component.ServiceClass!=null)
                {
                    statements.Add(new CodeAssignStatement(
                        new CodePropertyReferenceExpression(
                            new CodeVariableReferenceExpression(component.Site.Name),"ServiceInterface"),
                        new CodeTypeOfExpression(component.ServiceInterface)));
                    if (typeof(Microsoft.Xna.Framework.GameComponent).IsAssignableFrom(component.ServiceClass))
                    {
                        statements.Add(new CodeAssignStatement(
                            new CodePropertyReferenceExpression(
                                new CodeVariableReferenceExpression(component.Site.Name), "Component"),
                            new CodeObjectCreateExpression(component.ServiceClass, new CodeExpression[] { new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Game") })));
                    }
                    else
                    {
                        statements.Add(new CodeAssignStatement(
                            new CodePropertyReferenceExpression(
                                new CodeVariableReferenceExpression(component.Site.Name), "Component"),
                            new CodeObjectCreateExpression(component.ServiceClass, new CodeExpression[] { })));
                    }
                    if (component.Component != null)
                    {
                        CollectionCodeDomSerializer ccds = new CollectionCodeDomSerializer();
                        CodeStatementCollection csc = (CodeStatementCollection)ccds.SerializeMemberAbsolute(manager, component, TypeDescriptor.GetProperties(component)["Component"]);
                        foreach (CodeStatement cs in csc)
                        {
                            if (cs is CodeAssignStatement)
                            {
                                CodeAssignStatement cas = (CodeAssignStatement)cs;
                                if (cas.Left is CodePropertyReferenceExpression)
                                {
                                    CodePropertyReferenceExpression cpre = (CodePropertyReferenceExpression)cas.Left;
                                    if (cpre.TargetObject is CodePropertyReferenceExpression)
                                    {
                                        cpre = (CodePropertyReferenceExpression)cpre.TargetObject;
                                        if (cpre.PropertyName == "Component")
                                            ((CodePropertyReferenceExpression)cas.Left).TargetObject = new CodeCastExpression(component.ServiceClass, cpre);
                                    }
                                }
                            }
                            if (cs is CodeExpressionStatement)
                            {
                                if (((CodeExpressionStatement)cs).Expression is CodeMethodInvokeExpression)
                                {
                                    CodeMethodInvokeExpression cmie = (CodeMethodInvokeExpression)((CodeExpressionStatement)cs).Expression;
                                    if (cmie.Method.TargetObject is CodePropertyReferenceExpression)
                                    {
                                        CodePropertyReferenceExpression cpre = (CodePropertyReferenceExpression)cmie.Method.TargetObject;
                                        if (cpre.TargetObject is CodePropertyReferenceExpression)
                                        {
                                            cpre = (CodePropertyReferenceExpression)cpre.TargetObject;
                                            if (cpre.PropertyName == "Component")
                                                ((CodePropertyReferenceExpression)cmie.Method.TargetObject).TargetObject = new CodeCastExpression(component.ServiceClass, cpre);
                                        }
                                    }
                                }
                            }
                        }
                        statements.AddRange(csc);

                        statements.Add(
                            new CodeMethodInvokeExpression(
                                new CodePropertyReferenceExpression(
                                    new CodePropertyReferenceExpression(
                                        new CodeThisReferenceExpression(),
                                        "Game"),
                                    "Services"),
                                "AddService",
                                new CodeExpression[] { new CodeTypeOfExpression(component.ServiceInterface), new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(component.Site.Name), "Component") }));
                    }
                }
            }
            return statements;
        }
    }
}
